package com.example.llw.bluetooth;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Created by Doule on 2016/6/30.
 */

public class BluetoothScan {
    private Activity mActivity;
    private final String TAG = "BluetoothScan";
    // BLE management
    private boolean mBtAdapterEnabled = false;
    private boolean mBleSupported = true;
    private boolean mScanning = false;

    private static final int REQ_ENABLE_BT = 0;

    private BluetoothAdapter mBtAdapter = null;

    private BluetoothScanListener mBluetoothListener;
    private List<BleDeviceInfo> mDeviceInfoList;

    public BluetoothScan(Activity activity, BluetoothScanListener scanListener) {
        if (activity != null && scanListener != null) {
            mActivity = activity;
            mBluetoothListener = scanListener;
        }
        if (!activity.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_BLUETOOTH_LE)) {
            Log.e(TAG, "ble not supported");
            mBleSupported = false;
        }

        // Initializes a Bluetooth adapter. For API level 18 and above, get a
        // reference to BluetoothAdapter through BluetoothManager.
        BluetoothManager mBluetoothManager = (BluetoothManager) activity.getSystemService(Context.BLUETOOTH_SERVICE);
        mBtAdapter = mBluetoothManager.getAdapter();

        // Checks if Bluetooth is supported on the device.
        if (mBtAdapter == null) {
            Log.e(TAG, "bt not supported");
            mBleSupported = false;
        }
        mDeviceInfoList = new ArrayList<BleDeviceInfo>();
    }

    /**
     * Search for Bluetooth devices with the specified uuid.
     *
     * @param myUUID Specified search have this service Bluetooth.
     *               {@code LeScanCallback#onLeScan(BluetoothDevice,int,byte[]) }
     *               callback.
     */
    public void startScan(final UUID[] myUUID) {
        if (myUUID == null || myUUID.length < 1) {
            return;
        }
        mMyScanUUID = myUUID;
        scanInit();
    }

    /**
     * Search bluetooth devices.
     * <p>
     * {@code LeScanCallback#onLeScan(BluetoothDevice,int,byte[]) }
     * callback.
     */
    public void startScan() {
        mMyScanUUID = null;
        scanInit();
    }

    private boolean mInitialised = false;

    private void scanInit() {
        if (!mBleSupported) {
            Log.e(TAG, "BLE not supported on this device");
            return;
        }
        if (!mInitialised) {
            mBtAdapterEnabled = mBtAdapter.isEnabled();
            if (!mBtAdapterEnabled) {
                // Request BT adapter to be turned on
                Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                mActivity.startActivityForResult(enableIntent, REQ_ENABLE_BT);
            }else {
                startScanLeDevice();
            }
            mInitialised = true;
        } else {
            if (!mScanning) {
                //mDeviceInfoList.clear();
                startScanLeDevice();
            }
        }
    }

    /**
     * Stop search.
     */
    public void stopScan() {
        if (mScanning) {
            mScanning = false;
            //mScanView.updateGui(false);
            stopScanLeDevice();
        }
    }

    private Handler mHandler = new Handler();
    private Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            stopScanLeDevice();
        }
    };
    // Stops scanning after 10 seconds.
    private static final long SCAN_PERIOD = 10000;

    /*private boolean scanLeDevice(boolean enable) {
        if (enable) {
            mScanning = mBtAdapter.startLeScan(mLeScanCallback);
        } else {
            mScanning = false;
            mBtAdapter.stopLeScan(mLeScanCallback);
        }
        return mScanning;
    }*/

    private UUID[] mMyScanUUID;

    private boolean startScanLeDevice() {

        //mScanning = mBtAdapter.startLeScan(mLeScanCallback);
        if (mMyScanUUID != null && mMyScanUUID.length > 0) {
            Log.e(TAG, "startScanLeDevice with uuid  ");
            mScanning = mBtAdapter.startLeScan(mMyScanUUID, mLeScanCallback);
        } else {
            Log.e(TAG, "startScanLeDevice: with null ");
            mScanning = mBtAdapter.startLeScan(mLeScanCallback);
        }
        mHandler.postDelayed(mRunnable, SCAN_PERIOD);
        return mScanning;
    }

    private void stopScanLeDevice() {
        mHandler.removeCallbacks(mRunnable);
        mScanning = false;
        mBtAdapter.stopLeScan(mLeScanCallback);
    }

    // Device scan callback.
    // NB! Nexus 4 and Nexus 7 (2012) only provide one scan result per scan
    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

        public void onLeScan(final BluetoothDevice device, final int rssi,
                             final byte[] scanRecord) {
            mActivity.runOnUiThread(new Runnable() {
                public void run() {
                    // Filter devices
                    // if (checkDeviceFilter(device.getName())) {
                    if (!deviceInfoExists(device.getAddress())) {
                        // New device
                        BleDeviceInfo deviceInfo = createDeviceInfo(device, rssi);
                        addDevice(deviceInfo);
                    } else {
                        // Already in list, update RSSI info
                        BleDeviceInfo deviceInfo = findDeviceInfo(device);
                        deviceInfo.updateRssi(rssi);
                    }
                    mBluetoothListener.onScanBluetoothListenerCompleted(device, rssi, scanRecord);
                }
                //}

            });
        }
    };

    private BleDeviceInfo createDeviceInfo(BluetoothDevice device, int rssi) {
        BleDeviceInfo deviceInfo = new BleDeviceInfo(device, rssi);
        return deviceInfo;
    }

    private boolean deviceInfoExists(String address) {
        for (int i = 0; i < mDeviceInfoList.size(); i++) {
            if (mDeviceInfoList.get(i).getBluetoothDevice().getAddress()
                    .equals(address)) {
                return true;
            }
        }
        return false;
    }

    private BleDeviceInfo findDeviceInfo(BluetoothDevice device) {
        for (int i = 0; i < mDeviceInfoList.size(); i++) {
            if (mDeviceInfoList.get(i).getBluetoothDevice().getAddress()
                    .equals(device.getAddress())) {
                return mDeviceInfoList.get(i);
            }
        }
        return null;
    }

    /**
     * Get the list of search bluetooth device .
     *
     * @return bluetooth device's list .
     */
    public List<BleDeviceInfo> getDeviceInfoList() {
        return mDeviceInfoList;
    }

    private void addDevice(BleDeviceInfo device) {
        mDeviceInfoList.add(device);
    }

}
